<script setup>
import { ref, defineAsyncComponent } from 'vue';
import CodeBlock from '@components/CodeBlock.vue';

// 代码示例常量定义
const suspenseUsageExampleCode = `// 在模板中使用Suspense
// <suspense>
//   <template #default>
//     <AsyncComponent />
//   </template>
//   <template #fallback>
//     <div>加载中...</div>
//   </template>
// </suspense>`;

// 定义异步组件
const AsyncCounter = defineAsyncComponent({
  loader: () => new Promise((resolve) => {
    // 模拟网络延迟
    window.setTimeout(() => {
      resolve({
        template: `
          <div class="async-counter">
            <h4>异步加载的计数器组件</h4>
            <p>计数: {{ count }}</p>
            <button @click="count++">增加</button>
          </div>
        `,
        data() {
          return { count: 0 };
        }
      });
    }, 1000);
  }),
  loadingComponent: {
    template: '<div class="loading">加载中...</div>'
  },
  errorComponent: {
    template: '<div class="error">加载失败!</div>'
  },
  delay: 200,
  timeout: 3000
});

// 模拟异步数据获取
const fetchData = () => {
  return new Promise((resolve) => {
    // 使用全局setTimeout
    window.setTimeout(() => {
      resolve({
        title: 'Vue 3 Suspense 示例',
        content: '这是通过异步函数获取的数据',
        timestamp: new Date().toLocaleString()
      });
    }, 2000);
  });
};

// 定义异步函数组件
const AsyncDataComponent = {
  async setup() {
    const data = await fetchData();
    return { data };
  },
  template: `
    <div class="async-data">
      <h4>{{ data.title }}</h4>
      <p>{{ data.content }}</p>
      <p class="timestamp">时间: {{ data.timestamp }}</p>
    </div>
  `
};

// 错误处理状态
const showError = ref(false);
const toggleError = () => {
  showError.value = !showError.value;
};

// 错误抛出组件
const ErrorComponent = {
  setup() {
    // 模拟组件加载错误
    throw new Error('组件加载失败!');
  },
  template: '<div>这个组件不会被渲染</div>'
};

// 可控制的异步组件
const DelayedComponent = defineAsyncComponent({
  loader: () => new Promise((resolve, reject) => {
    window.setTimeout(() => {
      if (showError.value) {
        reject(new Error('故意抛出的错误'));
      } else {
        resolve({
          template: `
            <div class="delayed-component">
              <h4>延迟加载组件</h4>
              <p>这是一个可以控制加载状态的异步组件</p>
              <p>加载时间: {{ new Date().toLocaleTimeString() }}</p>
            </div>
          `
        });
      }
    }, 1500);
  }),
  loadingComponent: {
    template: '<div class="loading">加载延迟组件中...</div>'
  },
  errorComponent: {
    props: ['error'],
    template: '<div class="error">错误: {{ error.message }}</div>'
  }
});

// 多个异步组件
const AsyncComponent1 = defineAsyncComponent(() =>
  new Promise(resolve => {
    window.setTimeout(() => {
      resolve({
        template: '<div class="async-child">第一个子组件</div>'
      });
    }, 800);
  })
);

const AsyncComponent2 = defineAsyncComponent(() =>
  new Promise(resolve => {
    window.setTimeout(() => {
      resolve({
        template: '<div class="async-child">第二个子组件</div>'
      });
    }, 1200);
  })
);

const AsyncComponent3 = defineAsyncComponent(() =>
  new Promise(resolve => {
    window.setTimeout(() => {
      resolve({
        template: '<div class="async-child">第三个子组件</div>'
      });
    }, 1500);
  })
);

// 预加载控制
const preloadComponents = ref(false);
const PreloadableComponent = defineAsyncComponent(() => {
  return new Promise(resolve => {
    window.setTimeout(() => {
      resolve({
        template: '<div class="preloadable-component">预加载组件内容</div>'
      });
    }, 1000);
  });
});

// Suspense最佳实践说明
const suspenseBestPractices = [
  '使用Suspense处理异步加载的UI状态',
  '为异步组件提供加载状态和错误处理',
  '结合defineAsyncComponent实现代码分割',
  '使用Suspense包裹异步组件树',
  '避免在Suspense中使用过多的异步依赖'
];
</script>

<template>
  <div class="suspense-demo">
    <h2 class="demo-title">⏳ Vue 3 Suspense 演示</h2>

    <p class="demo-description">
      Suspense是Vue 3中处理异步组件加载和异步操作的内置组件，提供了优雅的加载状态和错误处理机制。
    </p>

    <div class="demo-grid">
      <!-- 基本异步组件演示 -->
      <div class="demo-card">
        <h3 class="card-title">基本异步组件</h3>
        <div class="demo-content">
          <p>使用defineAsyncComponent定义异步加载的组件，自动处理加载状态。</p>
          <suspense>
            <template #default>
              <AsyncCounter />
            </template>
            <template #fallback>
              <div class="loading">组件加载中...</div>
            </template>
          </suspense>
        </div>
      </div>

      <!-- 异步数据获取演示 -->
      <div class="demo-card">
        <h3 class="card-title">异步数据获取</h3>
        <div class="demo-content">
          <p>在setup函数中使用async/await获取数据，并通过Suspense显示加载状态。</p>
          <suspense>
            <template #default>
              <AsyncDataComponent />
            </template>
            <template #fallback>
              <div class="loading">数据加载中...</div>
            </template>
          </suspense>
        </div>
      </div>

      <!-- 错误处理演示 -->
      <div class="demo-card">
        <h3 class="card-title">错误处理</h3>
        <div class="demo-content">
          <div class="error-toggle">
            <label>
              <input type="checkbox" v-model="showError" />
              模拟错误
            </label>
          </div>
          <suspense>
            <template #default>
              <DelayedComponent />
            </template>
            <template #fallback>
              <div class="loading">加载中...</div>
            </template>
          </suspense>
        </div>
      </div>

      <!-- 多个异步组件演示 -->
      <div class="demo-card">
        <h3 class="card-title">多个异步组件</h3>
        <div class="demo-content">
          <p>展示如何使用Suspense处理多个异步加载的组件。</p>
          <suspense>
            <template #default>
              <div class="async-components-group">
                <AsyncComponent1 />
                <AsyncComponent2 />
                <AsyncComponent3 />
              </div>
            </template>
            <template #fallback>
              <div class="loading">加载多个组件中...</div>
            </template>
          </suspense>
        </div>
      </div>

      <!-- 嵌套Suspense演示 -->
      <div class="demo-card">
        <h3 class="card-title">嵌套Suspense</h3>
        <div class="demo-content">
          <p>展示嵌套Suspense的使用场景。</p>
          <suspense>
            <template #default>
              <div class="nested-suspense">
                <p>外层Suspense内容</p>
                <suspense>
                  <template #default>
                    <AsyncCounter />
                  </template>
                  <template #fallback>
                    <div class="loading small">内层加载中...</div>
                  </template>
                </suspense>
              </div>
            </template>
            <template #fallback>
              <div class="loading">外层加载中...</div>
            </template>
          </suspense>
        </div>
      </div>

      <!-- 最佳实践 -->
      <div class="demo-card">
        <h3 class="card-title">Suspense最佳实践</h3>
        <div class="demo-content">
          <ul class="best-practices">
            <li v-for="(practice, index) in suspenseBestPractices" :key="index">
              {{ practice }}
            </li>
          </ul>
        </div>
      </div>
    </div>

    <!-- 异步组件代码示例 -->
    <div class="code-section">
      <h3 class="section-title">异步组件定义示例</h3>
      <div class="code-snippet">
        <CodeBlock :code="`// 基本语法
  const AsyncComponent = defineAsyncComponent({
    // 加载组件的函数
    loader: () => import('./MyComponent.vue'),
    // 加载异步组件时使用的组件
    loadingComponent: LoadingComponent,
    // 加载失败时使用的组件
    errorComponent: ErrorComponent,
    // 延迟显示加载组件的时间
    delay: 200,
    // 超时时间
    timeout: 3000
  });

// 在模板中使用Suspense
// <suspense>
//   <template #default>
//     <AsyncComponent />
//   </template>
//   <template #fallback>
//     <div>加载中...</div>
//   </template>
// </suspense>`" language="javascript"></CodeBlock>
      </div>
    </div>
  </div>
</template>

<style scoped>
.suspense-demo {
  padding: 20px;
}

.demo-title {
  text-align: center;
  margin-bottom: 10px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.demo-description {
  text-align: center;
  margin-bottom: 30px;
  color: #666;
  max-width: 800px;
  margin-left: auto;
  margin-right: auto;
}

.demo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 20px;
  margin-bottom: 30px;
}

.demo-card {
  background: white;
  border-radius: 12px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  padding: 20px;
}

.card-title {
  color: #667eea;
  margin-bottom: 15px;
}

.demo-content {
  display: flex;
  flex-direction: column;
  gap: 15px;
}

/* 加载状态 */
.loading {
  padding: 20px;
  text-align: center;
  background-color: #f5f5f5;
  border-radius: 8px;
  color: #666;
  animation: pulse 1.5s infinite;
}

.loading.small {
  padding: 10px;
  font-size: 0.9rem;
}

@keyframes pulse {
  0% {
    opacity: 0.6;
  }

  50% {
    opacity: 1;
  }

  100% {
    opacity: 0.6;
  }
}

/* 错误状态 */
.error {
  padding: 20px;
  text-align: center;
  background-color: #ffebee;
  border-radius: 8px;
  color: #c62828;
}

/* 异步组件样式 */
.async-counter,
.async-data,
.delayed-component {
  padding: 20px;
  background-color: #f9f9f9;
  border-radius: 8px;
  border-left: 4px solid #667eea;
}

.async-counter button {
  padding: 5px 10px;
  background-color: #667eea;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  margin-top: 10px;
}

.async-counter button:hover {
  opacity: 0.9;
}

.timestamp {
  font-size: 0.9rem;
  color: #666;
  font-style: italic;
  margin-top: 10px;
}

/* 错误开关 */
.error-toggle {
  margin-bottom: 15px;
}

/* 异步组件组 */
.async-components-group {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.async-child {
  padding: 15px;
  background-color: #f0f0f0;
  border-radius: 6px;
  text-align: center;
}

/* 嵌套Suspense */
.nested-suspense {
  padding: 15px;
  background-color: #e8f5e9;
  border-radius: 8px;
  border: 1px solid #c8e6c9;
}

/* 最佳实践列表 */
.best-practices {
  padding-left: 20px;
}

.best-practices li {
  margin-bottom: 8px;
  color: #555;
}

/* 代码部分 */
.code-section {
  background: white;
  border-radius: 12px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  padding: 20px;
}

.section-title {
  color: #667eea;
  margin-bottom: 15px;
}

.code-snippet {
  background-color: #f5f5f5;
  border-radius: 8px;
  padding: 15px;
  overflow-x: auto;
}

.code-snippet pre {
  margin: 0;
  font-family: 'Courier New', Courier, monospace;
  font-size: 0.9rem;
  color: #333;
  white-space: pre-wrap;
  word-wrap: break-word;
}

/* 响应式调整 */
@media (max-width: 768px) {
  .demo-grid {
    grid-template-columns: 1fr;
  }
}
</style>